package com.ruoyi.device.controller;

import java.util.HashMap;
import java.util.Map;
import java.util.Date;
import java.text.SimpleDateFormat;
import javax.servlet.http.HttpServletRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import com.ruoyi.common.redis.service.RedisService;
import com.ruoyi.device.domain.UserAuthStatus;
import java.util.concurrent.TimeUnit;
import com.ruoyi.common.core.utils.StringUtils;
import com.ruoyi.system.api.domain.SysDictData;
import com.ruoyi.common.core.constant.CacheConstants;
import java.util.List;

/**
 * WiFi引导页面控制器
 * 
 * @author ruoyi
 * @date 2025-10-29
 */
@Controller
@RequestMapping("/guide")
public class GuideController 
{
    private static final Logger log = LoggerFactory.getLogger(GuideController.class);
    
    @Autowired
    private RedisService redisService;

    /**
     * 引导页面入口
     * 访问路径：http://route.tt-wf.com/guide/index.html
     * 
     * @param src 来源参数
     * @param macAddress MAC地址
     * @param deviceId 设备ID
     * @param channelId 渠道ID
     * @param timestamp 时间戳
     * @param sign 签名
     * @param sign_ver 签名版本
     * @param request HTTP请求对象
     * @param model 视图模型
     * @return 返回guide/index视图
     */
    @GetMapping({"/index.html", "/index"})
    public String index(
            @RequestParam(required = false) String src,
            @RequestParam(required = false) String macAddress,
            @RequestParam(required = false) String deviceId,
            @RequestParam(required = false) String channelId,
            @RequestParam(required = false) String timestamp,
            @RequestParam(required = false) String sign,
            @RequestParam(required = false) String sign_ver,
            HttpServletRequest request,
            Model model) 
    {
        try {
            // ==================== 这里可以添加您的业务逻辑 ====================
            
            // 1. 打印所有URL参数
            Map<String, String> allParams = getAllRequestParams(request);
            log.info("访问引导页面 - IP: {}", getClientIp(request));
            log.info("所有URL参数: {}", allParams);
            
            // 2. 记录关键参数
            // log.info("关键参数 - deviceId: {}, macAddress: {}, channelId: {}, timestamp: {}", 
            //         deviceId, macAddress, channelId, timestamp);
            
            // 3. 检查用户是否超过临时上网次数限制
            boolean isLimited = false;
            int banDuration = 30; // 默认封禁时长
            if (deviceId != null && !deviceId.trim().isEmpty() 
                && macAddress != null && !macAddress.trim().isEmpty()) {
                
                // 检查防刷限制
                isLimited = isTemporaryAccessLimited(deviceId, macAddress);
                if (isLimited) {
                    banDuration = getAntiAbuseBanDuration();
                    log.warn("【引导页】用户触发防刷限制: device={}, mac={}, 封禁时长={}分钟", 
                        deviceId, macAddress, banDuration);
                }
                
                // 添加频率限制：防止同一设备+MAC短时间内重复检查
                String limitKey = "guide:check:" + deviceId + ":" + macAddress;
                if (!Boolean.TRUE.equals(redisService.hasKey(limitKey))) {
                    // 检查并更新 Redis 认证状态
                    checkAndUpdateRedisAuthStatus(deviceId, macAddress);
                    // 设置3秒的频率限制
                    redisService.setCacheObject(limitKey, 1, 3L, TimeUnit.SECONDS);
                } else {
                    log.debug("引导页访问过于频繁，跳过认证检查: device={}, mac={}", deviceId, macAddress);
                }
            }
            
            // 4. 可以向模板传递动态数据（可选）
            model.addAttribute("deviceId", deviceId != null ? deviceId : "");
            model.addAttribute("macAddress", macAddress != null ? macAddress : "");
            model.addAttribute("timestamp", timestamp != null ? timestamp : "");
            model.addAttribute("isLimited", isLimited);
            model.addAttribute("banDuration", banDuration);
            
            // 例如：可以根据设备ID查询设备信息
            // DeviceInfo device = deviceInfoService.selectDeviceInfoById(deviceId);
            // model.addAttribute("deviceName", device != null ? device.getDeviceName() : "");
            
            // ==================== 业务逻辑结束 ====================
            
            // 返回视图（Thymeleaf会自动查找 templates/guide/index.html）
            return "guide/index";
            
        } catch (Exception e) {
            log.error("处理引导页面请求失败", e);
            // 出错时可以返回错误页面
            return "error/500";
        }
    }
    
    /**
     * 检查并更新 Redis 中的认证状态
     * 如果 Redis 记录存在且已过期，将 status 改为 2
     * 
     * @param deviceId 设备ID
     * @param macAddress MAC地址
     */
    private void checkAndUpdateRedisAuthStatus(String deviceId, String macAddress) {
        try {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            
            // 构建 Redis Key（与 IncomeController 中的格式保持一致）
            String redisKey = buildAuthRedisKey(deviceId, macAddress);
            
            // 从 Redis 获取认证状态
            UserAuthStatus authStatus = getAuthStatusFromRedis(redisKey);
            
            if (authStatus == null) {
                // Redis 中没有记录，不做任何操作
                log.info("【引导页】Redis 中没有认证记录: device={}, mac={}", deviceId, macAddress);
                return;
            }
            
            // 当前时间
            Date currentTime = new Date();
            Date expireTime = authStatus.getExpireTime();
            
            if (expireTime != null && currentTime.after(expireTime)) {
                // 已过期，将 status 改为 2
                authStatus.setStatus(2);
                
                // 更新 Redis
                saveAuthStatusToRedis(redisKey, authStatus);
                
                log.info("【引导页】✅ Redis 认证记录已过期，status 已更新为 2: device={}, mac={}, expireTime={}, currentTime={}",
                    deviceId, macAddress, sdf.format(expireTime), sdf.format(currentTime));
            } else {
                // 未过期，不做任何操作
                log.info("【引导页】Redis 认证记录未过期: device={}, mac={}, expireTime={}, status={}, adWatched={}",
                    deviceId, macAddress, expireTime != null ? sdf.format(expireTime) : "null", 
                    authStatus.getStatus(), authStatus.getAdWatched());
            }
            
        } catch (Exception e) {
            log.error("【引导页】检查并更新 Redis 认证状态失败: device={}, mac={}", deviceId, macAddress, e);
        }
    }
    
    /**
     * 构建 Redis Key
     * 格式: auth:{deviceId}:{macAddress}
     * （与 IncomeController 中的格式保持一致）
     */
    private String buildAuthRedisKey(String deviceId, String macAddress) {
        return "auth:" + deviceId + ":" + macAddress;
    }
    
    /**
     * 从 Redis 获取认证状态
     * 将 JSON 字符串反序列化为 UserAuthStatus 对象
     */
    private UserAuthStatus getAuthStatusFromRedis(String redisKey) {
        try {
            Object cacheObject = redisService.getCacheObject(redisKey);
            if (cacheObject == null) {
                return null;
            }
            
            // 如果 RedisService 返回的是 UserAuthStatus 对象（支持对象序列化）
            if (cacheObject instanceof UserAuthStatus) {
                return (UserAuthStatus) cacheObject;
            }
            
            // 如果返回的是 FastJson2 的 JSONObject，需要转换
            if (cacheObject instanceof com.alibaba.fastjson2.JSONObject) {
                com.alibaba.fastjson2.JSONObject jsonObject = (com.alibaba.fastjson2.JSONObject) cacheObject;
                return jsonObject.toJavaObject(UserAuthStatus.class);
            }
            
            // 其他类型
            log.warn("Redis 返回的对象类型不支持: {}", cacheObject.getClass().getName());
            return null;
            
        } catch (Exception e) {
            log.error("从 Redis 读取认证状态失败: key={}", redisKey, e);
            return null;
        }
    }
    
    /**
     * 保存认证状态到 Redis
     * 将 UserAuthStatus 对象序列化后存入 Redis
     */
    private void saveAuthStatusToRedis(String redisKey, UserAuthStatus authStatus) {
        try {
            redisService.setCacheObject(redisKey, authStatus);
            log.debug("保存认证状态到 Redis 成功: key={}", redisKey);
        } catch (Exception e) {
            log.error("保存认证状态到 Redis 失败: key={}", redisKey, e);
        }
    }
    
    /**
     * 获取所有请求参数
     */
    private Map<String, String> getAllRequestParams(HttpServletRequest request) {
        Map<String, String> params = new HashMap<>();
        Map<String, String[]> parameterMap = request.getParameterMap();
        
        for (Map.Entry<String, String[]> entry : parameterMap.entrySet()) {
            String key = entry.getKey();
            String[] values = entry.getValue();
            if (values != null && values.length > 0) {
                // 如果有多个值，用逗号连接
                params.put(key, values.length == 1 ? values[0] : String.join(",", values));
            }
        }
        
        return params;
    }
    
    /**
     * 获取客户端真实IP地址
     */
    private String getClientIp(HttpServletRequest request) {
        String ip = request.getHeader("X-Forwarded-For");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_CLIENT_IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_X_FORWARDED_FOR");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        // 处理多个IP的情况（取第一个）
        if (ip != null && ip.contains(",")) {
            ip = ip.split(",")[0].trim();
        }
        return ip;
    }
    
    /**
     * 检查用户是否触发防刷限制
     * 
     * @param deviceId 设备ID
     * @param macAddress MAC地址
     * @return true-已限制，false-未限制
     */
    private boolean isTemporaryAccessLimited(String deviceId, String macAddress) {
        try {
            int timeWindow = getAntiAbuseTimeWindow(); // 时间窗口（分钟）
            int maxCount = getAntiAbuseMaxCount(); // 最大次数
            
            String limitKey = "temp_access_limit:" + deviceId + ":" + macAddress;
            long currentTime = System.currentTimeMillis();
            long windowStartTime = currentTime - (timeWindow * 60 * 1000L);
            
            Object cacheObject = redisService.getCacheObject(limitKey);
            java.util.List<Long> accessTimes = new java.util.ArrayList<>();
            if (cacheObject instanceof com.alibaba.fastjson2.JSONArray) {
                com.alibaba.fastjson2.JSONArray jsonArray = (com.alibaba.fastjson2.JSONArray) cacheObject;
                accessTimes = jsonArray.toList(Long.class);
            }
            
            long finalWindowStartTime = windowStartTime;
            long validAccessCount = accessTimes.stream()
                .filter(time -> time >= finalWindowStartTime)
                .count();
            
            log.debug("【引导页】防刷检查: device={}, mac={}, 时间窗口={}分钟, 窗口内访问次数={}, 最大允许次数={}",
                deviceId, macAddress, timeWindow, validAccessCount, maxCount);
            
            return validAccessCount >= maxCount;
        } catch (Exception e) {
            log.error("【引导页】防刷检查异常: device={}, mac={}", deviceId, macAddress, e);
            return false;
        }
    }
    
    /**
     * 从字典获取防刷时间窗口配置（分钟）
     */
    private int getAntiAbuseTimeWindow() {
        return getDictIntValue("防刷时间窗口（分钟）", 30);
    }
    
    /**
     * 从字典获取防刷最大次数配置
     */
    private int getAntiAbuseMaxCount() {
        return getDictIntValue("防刷最大临时上网次数", 3);
    }
    
    /**
     * 从字典获取防刷封禁时长配置（分钟）
     */
    private int getAntiAbuseBanDuration() {
        return getDictIntValue("防刷封禁时长（分钟）", 30);
    }
    
    /**
     * 从字典获取整数配置值
     * 
     * @param dictLabel 字典标签
     * @param defaultValue 默认值
     * @return 配置值
     */
    private int getDictIntValue(String dictLabel, int defaultValue) {
        try {
            String dictType = "wifi_auth_config";
            String cacheKey = CacheConstants.SYS_DICT_KEY + dictType;
            
            Object cacheObj = redisService.getCacheObject(cacheKey);
            if (cacheObj == null) {
                log.warn("字典缓存不存在: dictType={}", dictType);
                return defaultValue;
            }
            
            List<SysDictData> dictDataList = null;
            if (cacheObj instanceof com.alibaba.fastjson2.JSONArray) {
                com.alibaba.fastjson2.JSONArray jsonArray = (com.alibaba.fastjson2.JSONArray) cacheObj;
                dictDataList = jsonArray.toList(SysDictData.class);
            }
            
            if (dictDataList == null || dictDataList.isEmpty()) {
                log.warn("字典数据为空: dictType={}", dictType);
                return defaultValue;
            }
            
            for (SysDictData dictData : dictDataList) {
                if (dictLabel.equals(dictData.getDictLabel())) {
                    String dictValue = dictData.getDictValue();
                    if (StringUtils.isNotEmpty(dictValue)) {
                        try {
                            return Integer.parseInt(dictValue);
                        } catch (NumberFormatException e) {
                            log.error("字典值不是有效的整数: label={}, value={}", dictLabel, dictValue);
                            return defaultValue;
                        }
                    }
                }
            }
            
            log.debug("未找到字典配置: label={}, 使用默认值={}", dictLabel, defaultValue);
            return defaultValue;
        } catch (Exception e) {
            log.error("获取字典配置失败: label={}, 使用默认值={}", dictLabel, defaultValue, e);
            return defaultValue;
        }
    }
}

